/*
Copyright (c) 2025 HeZongLun
NahidaProject is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan
PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/

#pragma once

#ifdef _WIN32
#define ExportSymbol  __declspec(dllexport)
#else
#define ExportSymbol
#endif

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <cstring>

namespace NahidaProject {
	class ExportSymbol SHA256 {
	private:
		uint32_t sha256K[64] = {
	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
		};
		uint32_t h[8];

		static inline uint32_t Rotr(uint32_t x, int n) {
			return (x >> n) | (x << (32 - n));
		}

		static inline uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) {
			return (x & y) ^ (~x & z);
		}

		static inline uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) {
			return (x & y) ^ (x & z) ^ (y & z);
		}

		static inline uint32_t Sigma0(uint32_t x) {
			return Rotr(x, 2) ^ Rotr(x, 13) ^ Rotr(x, 22);
		}

		static inline uint32_t Sigma1(uint32_t x) {
			return Rotr(x, 6) ^ Rotr(x, 11) ^ Rotr(x, 25);
		}

		static inline uint32_t Gamma0(uint32_t x) {
			return Rotr(x, 7) ^ Rotr(x, 18) ^ (x >> 3);
		}

		static inline uint32_t Gamma1(uint32_t x) {
			return Rotr(x, 17) ^ Rotr(x, 19) ^ (x >> 10);
		}

		void Initial();
		void ProcessBlock(const uint8_t* block);
		void ProcessFinalBlock(const uint8_t* data, size_t length, uint64_t totalBits);

	public:
		SHA256() {
			Initial();
		}

		std::vector<uint8_t> Hash(const std::string& input);
		std::vector<uint8_t> Hash(const std::vector<uint8_t>& input);
		static std::string BytesToHex(const std::vector<uint8_t>& bytes);
		std::string HashToString(const std::string& input);
	};
}
